package com.yeyks.controller;

import com.alibaba.fastjson.JSONObject;
import com.yeyks.base.Arguments;
import com.yeyks.constant.ConfigKey;
import com.yeyks.dal.dao.FeedbackMapper;
import com.yeyks.dal.domain.*;
import com.yeyks.dto.*;
import com.yeyks.exception.ServiceException;
import com.yeyks.exception.SmsSendException;
import com.yeyks.model.*;
import com.yeyks.model.Ajax.AjaxResponseBody;
import com.yeyks.model.em.AccountType;
import com.yeyks.model.em.ResponseStatus;
import com.yeyks.model.em.VipOrderStatus;
import com.yeyks.newwebsocket.WebSocket;
import com.yeyks.service.*;
import com.yeyks.util.*;
import com.yeyks.wxpay.WXJsapiPayService;
import com.yeyks.wxpay.impl.MyConfig;
import com.yeyks.base.Arguments;
import com.yeyks.dto.AppInfoDTO;
import com.yeyks.exception.ServiceException;
import com.yeyks.exception.SmsSendException;
import com.yeyks.model.Ajax.AjaxResponseBody;
import com.yeyks.model.OrderStatus;
import com.yeyks.model.PreOrderType;
import com.yeyks.model.em.AccountType;
import com.yeyks.model.em.ResponseStatus;
import com.yeyks.model.em.VipOrderStatus;
import com.yeyks.newwebsocket.WebSocket;
import com.yeyks.service.*;
import com.yeyks.util.DateUtils;
import com.yeyks.util.ObjectConvertUtil;
import com.yeyks.util.TextValidator;
import com.yeyks.util.Utility;
import com.yeyks.wxpay.impl.MyConfig;
import io.swagger.annotations.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import springfox.documentation.annotations.ApiIgnore;

import javax.servlet.http.HttpServletRequest;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.util.*;

/**
 * @Author fuchangshuai
 * @date 2019/2/27 11:19 AM
 * app端只返null, list , map
 */
@ApiIgnore
@Api(tags = "客户端新接口", description = "用户")
@Slf4j
@RestController
@RequestMapping(value = "/ajax/user")
public class UserInfoController {

    @Autowired
    private AccountService accountService;

    @Autowired
    private SmsService smsService;

    @Autowired
    private UserInfoService userInfoService;

    @Autowired
    private UserCouponService userCouponService;

    @Autowired
    private VipInfoService vipInfoService;

    @Autowired
    private FeedbackMapper feedbackMapper;

    @Autowired
    private DocInfoService docInfoService;

    @Autowired
    private HotelService hotelService;

    @Autowired
    private OrderService orderService;

    @Autowired
    private ConfigService configService;

    @Autowired
    private OssService ossService;

    @Autowired
    private RoomInfoService roomInfoService;

    @Autowired
    private VipOrderService vipOrderService;

    @Autowired
    private CouponInfoService couponInfoService;

    @Autowired
    private WXJsapiPayService wxJsapiPayService;

    @Autowired
    private PayService payService;

    @Autowired
    private ShareLogService shareLogService;

    @Autowired
    private WebSocket webSocket;

    @Autowired
    private AppInfoService appInfoService;

    @Autowired
    private CczcService cczcService;

    /**
     * 忘记密码发送验证码
     *
     * @param phone
     * @return
     */
    @ApiOperation(value = "忘记密码发送验证码")
    @ApiImplicitParam(paramType = "query", name = "phone", value = "手机号", required = true, dataType = "String")
    @PostMapping(value = "/forgetPwdGetCode")
    public ResponseEntity<?> getPasswordVerifyCode(@RequestParam(name = "phone") String phone) {
        checkParamPhone(phone);
        UserInfo userInfo = userInfoService.selectUseInfoPhone(phone);
        if (userInfo == null) {
            return ResponseEntity.ok(AjaxResponseBody.failed(-19950910, "该用户不存在"));
        }
        return sendMessage(phone);
    }

    private ResponseEntity<?> sendMessage(String phone) {
        AjaxResponseBody response = new AjaxResponseBody();
        if (phone == null) {
            // 2.输入的手机格式不对时，系统给出提示【手机格式不正确】。
            response.setCode(com.yeyks.model.em.ResponseStatus.RS_ACCOUNT_REG_INVALIDPHONE.getCode());
            response.setMsg(com.yeyks.model.em.ResponseStatus.RS_ACCOUNT_REG_INVALIDPHONE.getMsg());
        } else {
            try {
                smsService.sendSmsForSignup(phone);
                response.setBody(true);
                response.setCode(com.yeyks.model.em.ResponseStatus.RS_SUCCESS.getCode());
                response.setMsg(com.yeyks.model.em.ResponseStatus.RS_SUCCESS.getMsg());
            } catch (SmsSendException e) {

                if (e.getWait() == 0) {
                    response.setCode(com.yeyks.model.em.ResponseStatus.RS_ACCOUNT_SMSINVALID.getCode());
                    response.setMsg(com.yeyks.model.em.ResponseStatus.RS_ACCOUNT_SMSINVALID.getMsg());
                } else {
                    // 其它写入失败
                    Map<String, Object> map = new HashMap<>();
                    map.put("wait", e.getWait());
                    response.setBody(map);
                    response.setCode(com.yeyks.model.em.ResponseStatus.RS_ACCOUNT_SMSWAIT.getCode());
                    response.setMsg(com.yeyks.model.em.ResponseStatus.RS_ACCOUNT_SMSWAIT.getMsg());
                }
            } catch (ServiceException e) {
                // 其它写入失败
                response.setCode(-1);
                response.setMsg(e.getMessage());
            } catch (Throwable e) {
                // 其它写入失败
                response.setCode(com.yeyks.model.em.ResponseStatus.RS_FAIL.getCode());
                response.setMsg(ResponseStatus.RS_FAIL.getMsg());
            }
        }
        return ResponseEntity.ok(response);
    }

    /**
     * 用户登录
     *
     * @param code
     * @param phone
     * @param password
     * @return
     */
    @ApiOperation(value = "用户登陆", notes = "使用手机号验证码或者手机号密码登陆")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "query", name = "code", value = "验证码", dataType = "String"),
            @ApiImplicitParam(paramType = "query", name = "phone", value = "手机号", required = true, dataType = "String"),
            @ApiImplicitParam(paramType = "query", name = "password", value = "密码", dataType = "String"),
            @ApiImplicitParam(paramType = "query", name = "sourceType", value = "来源", defaultValue = "ios", dataType = "String")
    })
    @PostMapping(value = "/login")
    public ResponseEntity<?> loginV2(@RequestParam(name = "code", required = false) String code,
                                     @RequestParam(name = "phone") String phone,
                                     @RequestParam(name = "password", required = false) String password,
                                     @RequestParam(name = "sourceType", defaultValue = "ios") String sourceType) {
        //非验证码登陆
        if (code == null || code.isEmpty()) {
            checkParamPhonePwd(phone, password);
            //用户的话使用手机号密码登陆
            UserInfo userInfo = userInfoService.selectUseInfoPhone(phone);
            if (userInfo == null) {
                throw new ServiceException("该用户不存在");
            }
            if (!password.equals(userInfo.getPassword())) {
                throw new ServiceException("密码输入有误");
            }
            return packLoginResult(userInfo);
        }
        checkParamPhone(phone);
        if (smsService.verifySmsForSignup(phone, code)) {
            // 查找用户的所有信息
            UserInfo exist = userInfoService.selectUseInfoPhone(phone);
            if (exist != null) {
                return packLoginResult(exist);
            } else {
                UserInfo userInfo = new UserInfo();
                // 不保存密码
                userInfo.setNickname("User_" + UUID.randomUUID().toString().substring(0, 7));
                userInfo.setPassword(null);
                userInfo.setType(AccountType.User);
                userInfo.setPhone(phone);
                userInfo.setValid(true);
                userInfo.setStatus(1);
                userInfo.setSourceType(sourceType);
                userInfo.setIsDel(1);
                userInfo.setIsVip(0);
                userInfo.setInviteCode(Utility.invateCode());
                userInfoService.insertReturnId(userInfo);
                if (userInfo.getId() != null) {
                    //给新用户发两张10元优惠券
                    userCouponService.createNewCoupon(userInfo.getId());
                }
                return packLoginResult(userInfo);
            }
        } else {
            return ResponseEntity.ok(AjaxResponseBody.failed("验证码无效"));
        }
    }

    /**
     * 分享后用户通过手机号注册
     *
     * @param userId
     * @param phone
     * @return
     */
    @ApiOperation(value = "分享后用户通过手机号注册", notes = "分享后用户通过手机号注册")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "query", name = "userId", value = "分享人用户id", required = true, dataType = "int"),
            @ApiImplicitParam(paramType = "query", name = "phone", value = "手机号", required = true, dataType = "String"),
            @ApiImplicitParam(paramType = "query", name = "sourceType", value = "来源", defaultValue = "ios", dataType = "String")
    })
    @PostMapping(value = "/phone/login")
    public ResponseEntity<?> phoneLogin(@RequestParam(name = "userId") Integer userId,
                                        @RequestParam(name = "phone") String phone,
                                        @RequestParam(name = "sourceType", defaultValue = "ios") String sourceType) {
        checkParamPhoneUseId(phone, userId);
        //通过该手机号查询该用户是否存在
        UserInfo userInfo = userInfoService.selectUseInfoPhone(phone);
        if (userInfo != null) {
            log.info("该手机号已经存在{}", phone);
            throw new ServiceException("该手机号已注册");
        }
        userInfo = new UserInfo();
        userInfo.setNickname(Utility.randomName());
        userInfo.setPassword(Utility.randomPwd());
        userInfo.setType(AccountType.User);
        userInfo.setPhone(phone);
        userInfo.setValid(true);
        userInfo.setParentId(userId);
        userInfo.setSourceType(sourceType);
        userInfo.setIsDel(1);
        userInfo.setIsVip(0);
        userInfo.setInviteCode(Utility.invateCode());
        userInfo.setStatus(1);
        //保存注册用户信息，并给分享人送10元券，并且给注册人发送密码短信
        userInfoService.phoneLogin(userInfo);
        return ResponseEntity.ok(AjaxResponseBody.success());
    }

    /**
     * 判断当前用户是否存在
     *
     * @param phone
     * @return
     */
    @ApiOperation(value = "判断当前用户是否存在", notes = "通过手机号查询该用户是否存在")
    @ApiImplicitParam(paramType = "query", name = "phone", value = "手机号", required = true, dataType = "String")
    @PostMapping(value = "/userInfo")
    public ResponseEntity<?> userInfo(@RequestParam(name = "phone") String phone) {
        log.info("获取当前用户手机号{}", phone);
        checkParamPhone(phone);
        UserInfo operatorInfo = userInfoService.selectUseInfoPhone(phone);
        if (operatorInfo == null) {
            return ResponseEntity.ok(AjaxResponseBody.success(false));
        }
        return ResponseEntity.ok(AjaxResponseBody.success(true));
    }

    /**
     * 用户设置密码或忘记密码
     *
     * @param token
     * @param phone
     * @param password
     * @return
     */
    @ApiOperation(value = "用户设置密码或忘记密码", notes = "设置密码传入token和密码，忘记密码需先验证手机号，再传手机号和密码")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "query", name = "token", value = "token", dataType = "String"),
            @ApiImplicitParam(paramType = "query", name = "phone", value = "手机号", required = true, dataType = "String"),
            @ApiImplicitParam(paramType = "query", name = "password", value = "密码", required = true, dataType = "String")
    })
    @PostMapping(value = "/setPwd")
    public ResponseEntity<?> userSetPwd(@RequestParam(name = "token", required = false) String token,
                                        @RequestParam(name = "phone") String phone,
                                        @RequestParam(name = "password") String password
    ) {
        checkParamPhonePwd(phone, password);
        if (Arguments.isEmpty(token)) {//忘记密码，参数手机号和密码
            UserInfo userInfo = userInfoService.selectUseInfoPhone(phone);
            int rec = userInfoService.modifyPasswordById(userInfo.getId(), password);
            if (rec == 0) {
                throw new ServiceException("修改数据失败");
            }
            return ResponseEntity.ok(AjaxResponseBody.success());
        }
        //第一次设置密码，token和密码
        UserInfo operatorInfo = accountService.tokenUserInfo(token);
        if (!operatorInfo.getPhone().equals(phone)) {
            throw new ServiceException("拒绝非本人操作");
        }
        int rec = userInfoService.modifyPasswordById(operatorInfo.getId(), password);
        if (rec == 0) {
            throw new ServiceException("修改数据失败");
        }
        return ResponseEntity.ok(AjaxResponseBody.success());
    }

    /**
     * 用户修改密码
     *
     * @param token
     * @param origPwd
     * @param id
     * @param password
     * @return
     */
    @ApiOperation(value = "用户修改密码", notes = "注意验证两次密码输入是否一致")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "query", name = "token", value = "token", required = true, dataType = "String"),
            @ApiImplicitParam(paramType = "query", name = "origPwd", value = "原始密码", required = true, dataType = "String"),
            @ApiImplicitParam(paramType = "query", name = "id", value = "用户id", required = true, dataType = "int"),
            @ApiImplicitParam(paramType = "query", name = "password", value = "新密码", required = true, dataType = "String")
    })
    @PostMapping(value = "/modifyPassword")
    public ResponseEntity<?> modifyPassword(@RequestParam(name = "token") String token,
                                            @RequestParam(name = "origPwd") String origPwd,
                                            @RequestParam(name = "id") Integer id,
                                            @RequestParam(name = "password") String password) {

        checkParamPwd(password);
        UserInfo operatorInfo = accountService.tokenUserInfo(token);
        if (!operatorInfo.getId().equals(id)) {
            throw new ServiceException("当前操作人非本人");
        }
        UserInfo origAccountInfo = userInfoService.selectByPrimaryKey(id);
        if (!origPwd.equals(origAccountInfo.getPassword())) {
            throw new ServiceException("原密码输入有误");
        }

        int rec = userInfoService.modifyPasswordById(id, password);
        if (rec == 0) {
            throw new ServiceException("更新密码失败");
        }

        return ResponseEntity.ok(AjaxResponseBody.success());
    }

    /**
     * 根据一定条件查询当前用户的优惠券
     *
     * @param token
     * @param useStatus 优惠券状态, 默认1未使用，2已使用，3已过期
     * @param price     满减的价格
     * @param pageNum
     * @param pageSize
     * @return
     */
    @ApiOperation(value = "根据一定条件查询当前用户的优惠券", notes = "当需要获取满减券时传入price")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "query", name = "token", value = "token", required = true, dataType = "String"),
            @ApiImplicitParam(paramType = "query", name = "useStatus", value = "优惠券状态, 默认1未使用，2已使用，3已过期", defaultValue = "1", dataType = "int"),
            @ApiImplicitParam(paramType = "query", name = "price", value = "满减的价格", dataType = "int"),
            @ApiImplicitParam(paramType = "query", name = "pageNum", value = "当前页", defaultValue = "1", dataType = "int"),
            @ApiImplicitParam(paramType = "query", name = "pageSize", value = "每页个数", defaultValue = "10", dataType = "int")
    })
    @PostMapping(value = "/coupon/list")
    public ResponseEntity<?> couponList(@RequestParam(name = "token") String token,
                                        @RequestParam(name = "useStatus", defaultValue = "1") Integer useStatus,
                                        @RequestParam(name = "price", required = false) Integer price,
                                        @RequestParam(name = "pageNum", defaultValue = "1") Integer pageNum,
                                        @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize) {
        UserInfo userInfo = accountService.tokenUserInfo(token);
        Map<String, Object> map = userCouponService.selectUserCouponList(userInfo.getId(), useStatus, price, pageNum, pageSize);
        return ResponseEntity.ok(AjaxResponseBody.success(map));
    }

    /**
     * 增加一条反馈
     *
     * @param token
     * @param content
     * @param title
     * @return
     */
    @ApiOperation(value = "增加一条反馈", notes = "增加一条反馈")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "query", name = "token", value = "token", required = true, dataType = "String"),
            @ApiImplicitParam(paramType = "query", name = "content", value = "内容", required = true, dataType = "String"),
            @ApiImplicitParam(paramType = "query", name = "title", value = "标题", required = true, dataType = "String")
    })
    @PostMapping(value = "/feedback/add")
    public ResponseEntity<?> add(@RequestParam(name = "token") String token,
                                 @RequestParam(name = "content") String content,
                                 @RequestParam(name = "title") String title) {
        if (Arguments.notEmpty(title)) {
            title = title.replaceAll("\\n", "");
            title = title.replaceAll("\\s", "");
        }
        if (Arguments.notEmpty(content)) {
            content = content.replaceAll("\\n", "");
            content = content.replaceAll("\\s", "");
        }
        if (!Arguments.notEmpty(title)) {
            throw new ServiceException("标题输入不能为空");
        }
        if (!Arguments.notEmpty(content)) {
            throw new ServiceException("内容输入不能为空");
        }
        if (title.length() > 15) {
            throw new ServiceException("标题长度不能大于15");
        }
        if (content.length() > 180) {
            throw new ServiceException("内容长度不能大于180");
        }
        content = UnicodeUtils.unicodeToString(content);
        title = UnicodeUtils.unicodeToString(title);
        UserInfo userInfo = accountService.tokenUserInfo(token);
        Feedback feedback = new Feedback();
        feedback.setUserId(userInfo.getId());
        feedback.setUserName(userInfo.getUsername());
        feedback.setUserPhone(userInfo.getPhone());
        feedback.setContent(content);
        feedback.setTitle(title);
        feedback.setReport(false);
        feedback.setReaded(false);
        int rec = feedbackMapper.insertReturnId(feedback);
        if (rec == 0) {
            throw new ServiceException("updated 0 row.");
        }
        return ResponseEntity.ok(AjaxResponseBody.success());
    }

    /**
     * 用户获取文档列表
     *
     * @param parent
     * @param keyword
     * @param pageNum
     * @param pageSize
     * @return
     */
    @ApiOperation(value = "用户获取文档列表", notes = "用户获取文档列表")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "query", name = "parent", value = "是否是分类，默认0内容，1分类", defaultValue = "0", dataType = "int"),
            @ApiImplicitParam(paramType = "query", name = "keyword", value = "关键字", dataType = "String"),
            @ApiImplicitParam(paramType = "query", name = "pageNum", value = "当前页", defaultValue = "1", dataType = "int"),
            @ApiImplicitParam(paramType = "query", name = "pageSize", value = "每页个数", defaultValue = "10", dataType = "int")
    })
    @PostMapping(value = "/utility/doc/list")
    public ResponseEntity<?> docList(
            @RequestParam(name = "parent", defaultValue = "0") Integer parent,
            @RequestParam(name = "keyword", required = false) String keyword,
            @RequestParam(name = "pageNum", defaultValue = "1") Integer pageNum,
            @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize) {
        if (Arguments.notEmpty(keyword)) {
            keyword = UnicodeUtils.unicodeToString(keyword);
        }
        Map<String, Object> map = docInfoService.selectDocByPage(parent, keyword, pageNum, pageSize);
        return ResponseEntity.ok(AjaxResponseBody.success(map));
    }

//    /**
//     * 获取如何退款
//     *
//     * @param hotelId
//     * @return
//     */
//    @ApiOperation(value = "获取退款规则")
//    @ApiImplicitParam(paramType = "query", name = "hotelId", value = "酒店id", required = true, dataType = "int")
//    @PostMapping(value = "/getRefund")
//    public ResponseEntity<?> docRefund(@RequestParam(name = "hotelId") Integer hotelId) {
//        HotelInfo hotelInfo = hotelService.selectHotelInfoById(hotelId);
//        if (hotelInfo == null || hotelInfo.getRefundCfg() == null) {
//            return ResponseEntity.ok(AjaxResponseBody.success(getRefund(null, null)));
//        }
//        JSONObject map = JSONObject.parseObject(hotelInfo.getRefundCfg());
//        Integer zero = (Integer) map.get("0");
//        Integer six = (Integer) map.get("6");
//        return ResponseEntity.ok(AjaxResponseBody.success(getRefund(zero, six)));
//    }
//
//    private List<String> getRefund(Integer zero, Integer six) {
//        List<String> list = new ArrayList<>();
//        if (zero == null || six == null) {
//            list.add("1.以入住当天12点为基准");
//            list.add("2.到达入住时间收取100%费用");
//            list.add("3.6小时内取消收取房费的5%的手续费");
//            list.add("4.提前6小时取消全额退款");
//            list.add("5.下单后30分钟未付款将取消订单");
//            return list;
//        }
//        Integer zeroPercent = zero * 100 / 1000;
//        Integer sixPercent = six * 100 / 1000;
//        list.add("1.以入住当天12点为基准");
//        list.add("2.到达入住时间收取" + zeroPercent + "%费用");
//        list.add("3.6小时内取消收取房费的" + sixPercent + "%的手续费");
//        list.add("4.提前6小时取消全额退款");
//        list.add("5.下单后30分钟未付款将取消订单");
//        return list;
//    }
    /**
     * 获取如何退款
     *
     * @param hotelId
     * @return
     */
    @ApiOperation(value = "获取退款规则")
    @ApiImplicitParam(paramType = "query", name = "hotelId", value = "酒店id", required = true, dataType = "int")
    @PostMapping(value = "/getRefund")
    public ResponseEntity<?> docRefund(@RequestParam(name = "hotelId") Integer hotelId) {
        return ResponseEntity.ok(AjaxResponseBody.success(getRefund()));
    }

    private List<String> getRefund() {
        List<String> list = new ArrayList<>();
        list.add("1.以入住当天18:00为基准");
        list.add("2.18:00点之前全额退款");
        list.add("3.18:00点之后不能退款");
        list.add("4.下单后30分钟未付款将取消订单");
        return list;
    }

    /**
     * 用户设置头像(后台管理使用)
     *
     * @param token
     * @return
     */
    @ApiOperation(value = "用户设置头像(后台管理使用)")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "query", name = "token", value = "token", required = true, dataType = "String"),
            @ApiImplicitParam(paramType = "query", name = "avatar", value = "用户头像", required = true, dataType = "String")
    })
    @PostMapping(value = "/set/avatar")
    public ResponseEntity<?> setAvatar(@RequestParam(name = "token") String token,
                                       @RequestParam(name = "avatar") String avatar) {
        checkParamAvatar(avatar);
        UserInfo userInfo = accountService.tokenUserInfo(token);
        Integer res = userInfoService.updateAvatar(userInfo.getId(), avatar);
        if (res != 1) {
            throw new ServiceException("更新用户头像失败");
        }
        return ResponseEntity.ok(AjaxResponseBody.success());
    }

    /**
     * 用户搜索酒店
     *
     * @param city      城市名称，例：北京
     * @param checkIn   check-in日期，时间戳
     * @param checkOut  check-out日期，时间戳
     * @param price     价格（单位：分），默认值（0不限价），例：20000 （200元）
     * @param starLevel 星级：默认0查询全部，2民宿，3星级，6商务
     * @param keyword   关键字，按照酒店名称
     * @param order     推荐(排序)模式：order 0智能排序（默认是这个,按照评分降序），1距离（按照距离升序），2价格（按照价格升序），3价格（按照价格降序）
     * @param pageNum   当前页
     * @param pageSize  页码
     * @param positionX 经度
     * @param positionY 纬度
     * @return
     */
    @ApiOperation(value = "用户搜索酒店")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "query", name = "city", value = "城市名称", required = true, dataType = "String"),
            @ApiImplicitParam(paramType = "query", name = "checkIn", value = "入住时间", required = true, dataType = "Long"),
            @ApiImplicitParam(paramType = "query", name = "checkOut", value = "离开时间", required = true, dataType = "Long"),
            @ApiImplicitParam(paramType = "query", name = "price", value = "价格(分)", required = true, dataType = "int"),
            @ApiImplicitParam(paramType = "query", name = "starLevel", value = "星级(默认0查询全部，2民宿，3星级，6商务)", defaultValue = "0", dataType = "int"),
            @ApiImplicitParam(paramType = "query", name = "keyword", value = "关键字", dataType = "String"),
            @ApiImplicitParam(paramType = "query", name = "order", value = "0智能排序（默认是这个,按照评分降序），1距离（按照距离升序），2价格（按照价格升序），3价格（按照价格降序）", defaultValue = "0", dataType = "int"),
            @ApiImplicitParam(paramType = "query", name = "pageNum", value = "当前页", defaultValue = "1", dataType = "int"),
            @ApiImplicitParam(paramType = "query", name = "pageSize", value = "页码", defaultValue = "10", dataType = "int"),
            @ApiImplicitParam(paramType = "query", name = "positionX", value = "经度", required = true, dataType = "Double"),
            @ApiImplicitParam(paramType = "query", name = "positionY", value = "纬度", required = true, dataType = "Double")
    })
    @RequestMapping(value = "/search/hotel", method = RequestMethod.POST)
    public ResponseEntity<?> searchHotel(@RequestParam(name = "city") String city,
                                         @RequestParam(name = "checkIn") Long checkIn,
                                         @RequestParam(name = "checkOut") Long checkOut,
                                         @RequestParam(name = "price") Integer price,
                                         @RequestParam(name = "starLevel", defaultValue = "0") Integer starLevel,
                                         @RequestParam(name = "keyword", required = false) String keyword,
                                         @RequestParam(name = "order", defaultValue = "0") Integer order,
                                         @RequestParam(name = "pageNum", defaultValue = "1") Integer pageNum,
                                         @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
                                         @RequestParam(name = "positionX") Double positionX,
                                         @RequestParam(name = "positionY") Double positionY) {
        if (Arguments.notEmpty(city)) {
            city = UnicodeUtils.unicodeToString(city);
        }
        Map<String, Object> map = hotelService.searchHotel(city, checkIn, checkOut, price, starLevel, keyword, order, pageNum, pageSize, positionX, positionY);
        return ResponseEntity.ok(AjaxResponseBody.success(map));
    }

    @ApiOperation(value = "用户搜索酒店(新接口)")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "query", name = "city", value = "城市名称", required = true, dataType = "String"),
            @ApiImplicitParam(paramType = "query", name = "checkIn", value = "入住时间(1554739200000)", required = true, dataType = "Long"),
            @ApiImplicitParam(paramType = "query", name = "checkOut", value = "离开时间(1554825600000)", required = true, dataType = "Long"),
            @ApiImplicitParam(paramType = "query", name = "price", value = "价格(分)", required = true, dataType = "int"),
            @ApiImplicitParam(paramType = "query", name = "starLevel", value = "星级(默认0查询全部，2民宿，3星级，6商务)", defaultValue = "0", dataType = "int"),
            @ApiImplicitParam(paramType = "query", name = "positionX", value = "经度(120.117924)", required = true, dataType = "Double"),
            @ApiImplicitParam(paramType = "query", name = "positionY", value = "纬度(30.329453)", required = true, dataType = "Double")
    })
    @RequestMapping(value = "/search/hotel/new", method = RequestMethod.POST)
    public ResponseEntity<?> searchHotelNew(@RequestParam(name = "city") String city,
                                         @RequestParam(name = "checkIn") Long checkIn,
                                         @RequestParam(name = "checkOut") Long checkOut,
                                         @RequestParam(name = "price") Integer price,
                                         @RequestParam(name = "starLevel", defaultValue = "0") Integer starLevel,
                                         @RequestParam(name = "positionX") Double positionX,
                                         @RequestParam(name = "positionY") Double positionY) {
        if (Arguments.notEmpty(city)) {
            city = UnicodeUtils.unicodeToString(city);
        }
        Map<String, Object> map = hotelService.searchHotelNew(city, checkIn, checkOut, price, starLevel, positionX, positionY);
        return ResponseEntity.ok(AjaxResponseBody.success(map));
    }

    /**
     * 通过酒店的id查询酒店的详情
     *
     * @param hotelId
     * @return
     */
    @ApiOperation(value = "通过酒店的id查询酒店的详情")
    @ApiImplicitParam(paramType = "query", name = "hotelId", value = "酒店id", required = true, dataType = "int")
    @RequestMapping(value = "/hotel/detail", method = RequestMethod.POST)
    public ResponseEntity<?> hotelDetail(@RequestParam(name = "hotelId") Integer hotelId) {
        HotelInfoDTO hotelInfoDTO = hotelService.selectHotelRoomDetail(hotelId);
        return ResponseEntity.ok(AjaxResponseBody.success(hotelInfoDTO));
    }

    /**
     * 通过房间id获取房间详情
     *
     * @param roomId
     * @return
     */
    @ApiOperation(value = "通过房间id获取房间详情")
    @ApiImplicitParam(paramType = "query", name = "roomId", value = "房间id", required = true, dataType = "int")
    @RequestMapping(value = "/room/detail", method = RequestMethod.POST)
    public ResponseEntity<?> roomDetail(@RequestParam(name = "roomId") Integer roomId) {
        RoomInfoDetailDTO roomInfoDetail = roomInfoService.roomDetail(roomId);
        return ResponseEntity.ok(AjaxResponseBody.success(roomInfoDetail));
    }

    /**
     * 查询各状态的订单数
     *
     * @param token
     * @param pageNum
     * @param pageSize
     * @param type     默认1全部，2已付款，3未支付，4已取消
     * @return
     */
    @ApiOperation(value = "查询各状态的订单数", notes = "查询各状态的订单数")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "query", name = "token", value = "token", required = true, dataType = "String"),
            @ApiImplicitParam(paramType = "query", name = "pageNum", value = "当前页", defaultValue = "1", dataType = "int"),
            @ApiImplicitParam(paramType = "query", name = "pageSize", value = "每页个数", defaultValue = "10", dataType = "int"),
            @ApiImplicitParam(paramType = "query", name = "type", value = "默认1全部，2已付款，3未支付，4已取消", defaultValue = "1", dataType = "int")
    })
    @RequestMapping(value = "/order/list", method = RequestMethod.POST)
    public ResponseEntity<?> list(@RequestParam(name = "token") String token,
                                  @RequestParam(name = "pageNum", defaultValue = "1") Integer pageNum,
                                  @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
                                  @RequestParam(name = "type", defaultValue = "1") Integer type
    ) {
        UserInfo userInfo = accountService.tokenUserInfo(token);
        List<OrderInfoDTO> orderInfos = orderService.selectOrderList(userInfo.getId(), pageNum, pageSize, type);
        return ResponseEntity.ok(AjaxResponseBody.success(orderInfos));
    }

    /**
     * 用户删除订单
     *
     * @param token
     * @param orderNo
     * @return
     */
    @ApiOperation(value = "用户删除订单", notes = "用户删除订单")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "query", name = "token", value = "token", required = true, dataType = "String"),
            @ApiImplicitParam(paramType = "query", name = "orderNo", value = "订单号", required = true, dataType = "String")
    })
    @RequestMapping(value = "/order/delete", method = RequestMethod.POST)
    public ResponseEntity<?> orderDelete(@RequestParam(name = "token") String token,
                                         @RequestParam(name = "orderNo") String orderNo) {
        UserInfo userInfo = accountService.tokenUserInfo(token);
        checkParamOrderNo(orderNo);
        OrderInfo orderInfo = orderService.selectOrderByOrderNo(orderNo);
        if (orderInfo == null) {
            throw new ServiceException("该订单号不存在");
        }
        if (!orderInfo.getUserId().equals(userInfo.getId())) {
            throw new ServiceException("非本人订单");
        }
        Integer res = orderService.updateOrderStatus(orderNo, OrderStatus.delete);
        if (res != 1) {
            log.info("更新删除状态失败");
        }
        return ResponseEntity.ok(AjaxResponseBody.success());
    }

    /**
     * 用户确认订单（生成订单并返回给客户端相应参数）
     *
     * @param token
     * @param checkInDate  入住时间
     * @param checkOutDate 离开时间
     * @param count        预定的房间间数
     * @param remark       备注
     * @param couponId     券id
     * @param name         下单用户真实姓名
     * @param phone        下单用户手机号
     * @return
     */
    @ApiOperation(value = "用户确认订单")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "query", name = "token", value = "token", required = true, dataType = "String"),
            @ApiImplicitParam(paramType = "query", name = "checkInDate", value = "入住时间", required = true, dataType = "Long"),
            @ApiImplicitParam(paramType = "query", name = "checkOutDate", value = "离开时间", required = true, dataType = "Long"),
            @ApiImplicitParam(paramType = "query", name = "count", value = "预定的房间数", defaultValue = "1", dataType = "int"),
            @ApiImplicitParam(paramType = "query", name = "remark", value = "备注", dataType = "String"),
            @ApiImplicitParam(paramType = "query", name = "couponId", value = "券id", defaultValue = "0", dataType = "int"),
            @ApiImplicitParam(paramType = "query", name = "roomId", value = "房间id", required = true, dataType = "int"),
            @ApiImplicitParam(paramType = "query", name = "type", value = "付款类型(wxpay,alipay)", dataType = "String"),
            @ApiImplicitParam(paramType = "query", name = "name", value = "下单用户真实姓名", required = true, dataType = "String"),
            @ApiImplicitParam(paramType = "query", name = "phone", value = "下单用户手机号", required = true, dataType = "String")
    })
    @RequestMapping(value = "/order/preOrder", method = RequestMethod.POST)
    public ResponseEntity<?> preOrder(@RequestParam(name = "token") String token,
                                      @RequestParam(name = "checkInDate") Long checkInDate,
                                      @RequestParam(name = "checkOutDate") Long checkOutDate,
                                      @RequestParam(name = "count", defaultValue = "1") Integer count,
                                      @RequestParam(name = "remark") String remark,
                                      @RequestParam(name = "couponId", defaultValue = "0") Integer couponId,
                                      @RequestParam(name = "roomId") Integer roomId,
                                      @RequestParam(name = "type") String type,
                                      @RequestParam(name = "name") String name,
                                      @RequestParam(name = "phone") String phone,
                                      HttpServletRequest request) {

        OrderInfo param = getOrderInfo(name, phone);
        //判断checkInDate是否小于今天
//        checkCheckInDate(checkInDate);
        UserInfo userInfo = accountService.tokenUserInfo(token);
        String ip = Utility.getRemoteIP(request);
        Map<String, String> map = orderService.preOrder(userInfo, param, checkInDate, checkOutDate, count, remark, couponId, roomId, type, ip);
        return ResponseEntity.ok(AjaxResponseBody.success(map));
    }

    private void checkCheckInDate(Long checkInDate) {
        Date inDate = DateUtils.stampToDate(checkInDate);
        Date nowDate = DateUtils.localDateToDate(LocalDate.now());
        if (DateUtils.dateCompareDate(nowDate, inDate)) {
            throw new ServiceException("不能预定今天前的订单");
        }
    }

    /**
     * h5用户确认订单
     *
     * @param token
     * @param checkInDate  入住时间
     * @param checkOutDate 离开时间
     * @param count        预定的房间间数
     * @param remark       备注
     * @param couponId     券id
     * @param name         下单用户真实姓名
     * @param phone        下单用户手机号
     * @return
     */
    @ApiOperation(value = "h5用户确认订单")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "query", name = "token", value = "token", required = true, dataType = "String"),
            @ApiImplicitParam(paramType = "query", name = "checkInDate", value = "入住时间", required = true, dataType = "Long"),
            @ApiImplicitParam(paramType = "query", name = "checkOutDate", value = "离开时间", required = true, dataType = "Long"),
            @ApiImplicitParam(paramType = "query", name = "count", value = "预定的房间数", defaultValue = "1", dataType = "int"),
            @ApiImplicitParam(paramType = "query", name = "remark", value = "备注", dataType = "String"),
            @ApiImplicitParam(paramType = "query", name = "couponId", value = "券id", defaultValue = "0", dataType = "int"),
            @ApiImplicitParam(paramType = "query", name = "roomId", value = "房间id", required = true, dataType = "int"),
            @ApiImplicitParam(paramType = "query", name = "name", value = "下单用户真实姓名", required = true, dataType = "String"),
            @ApiImplicitParam(paramType = "query", name = "phone", value = "下单用户手机号", required = true, dataType = "String"),
            @ApiImplicitParam(paramType = "query", name = "code", value = "用户code", dataType = "String"),
            @ApiImplicitParam(paramType = "query", name = "sourceType", value = "sourceType", defaultValue = "wx", dataType = "String")
    })
    @RequestMapping(value = "/order/h5/preOrder", method = RequestMethod.POST)
    public ResponseEntity<?> h5PreOrder(@RequestParam(name = "token") String token,
                                      @RequestParam(name = "checkInDate") Long checkInDate,
                                      @RequestParam(name = "checkOutDate") Long checkOutDate,
                                      @RequestParam(name = "count", defaultValue = "1") Integer count,
                                      @RequestParam(name = "remark") String remark,
                                      @RequestParam(name = "couponId", defaultValue = "0") Integer couponId,
                                      @RequestParam(name = "roomId") Integer roomId,
                                      @RequestParam(name = "name") String name,
                                      @RequestParam(name = "phone") String phone,
                                      @RequestParam(name = "code") String code,
                                      @RequestParam(name = "sourceType", defaultValue = "wx") String sourceType,
                                      HttpServletRequest request) {
        OrderInfo param = getOrderInfo(name, phone);
        int orderType = PreOrderType.parse(sourceType);
        //true代表是公众号，false代表小程序
        boolean flag = orderType == PreOrderType.wx || orderType == PreOrderType.h5;
        String type = "xcx";
        if (flag) {
            type = "gzh";
        }
//        UserInfo userInfo = accountService.tokenUserInfo(token);
        UserInfo userInfo = userInfoService.tokenUserInfo(token);
        //检测是否该用户是否有openid
        String openId = checkOpenid(userInfo, code, flag);
//        String openId = alwayGetOpenid(code, flag);
        String ip = Utility.getRemoteIP(request);
        Map<String, String> map = orderService.h5PreOrder(userInfo, param, checkInDate, checkOutDate, count, remark, couponId, roomId, type, ip, openId, flag);
        return ResponseEntity.ok(AjaxResponseBody.success(map));
    }

    private String checkOpenid(UserInfo userInfo, String code, Boolean flag) {
        JSONObject jsonObject = JSONObject.parseObject(userInfo.getExtraInfo());
        //公众号
        if (flag) {
            String gzhOpenId = null;
            if (jsonObject != null) {
                gzhOpenId = (String) jsonObject.get("gzhOpenId");
            }
            if (gzhOpenId != null) {
                return gzhOpenId;
            }
            if (!Arguments.notEmpty(code)) {
                throw new ServiceException("openid为空");
            }
            try {
                MyConfig config = new MyConfig();
                Utility.switchConfig(true, null, config);
                JSONObject jsonObjectv2 = payService.wxParseCode(true, code, config);
                gzhOpenId = jsonObjectv2.get("openid").toString();
            } catch (Throwable e) {
                log.info("获取xcxOpenId失败{}", code);
                throw new ServiceException("获取公众号OpenId失败");
            }
            Map<String, Object> map = new HashMap<>();
            map.put("gzhOpenId", gzhOpenId);
            if (jsonObject != null) {
                String xcxOpenId = (String) jsonObject.get("xcxOpenId");
                if (Arguments.notEmpty(xcxOpenId)) {
                    map.put("xcxOpenId", xcxOpenId);
                }
            }
            userInfo.setExtraInfo(JSONObject.toJSONString(map));
            Integer res = userInfoService.updateExtraInfoById(userInfo.getId(), userInfo.getExtraInfo());
            if (res != 1) {
                throw new ServiceException("更新openid失败");
            }
            return gzhOpenId;
        }
        String xcxOpenId = null;
        if (jsonObject != null) {
            xcxOpenId = (String) jsonObject.get("xcxOpenId");
        }
        if (xcxOpenId != null) {
            return xcxOpenId;
        }
        if (!Arguments.notEmpty(code)) {
            throw new ServiceException("openid为空");
        }
        try {
            MyConfig config = new MyConfig();
            Utility.switchConfig(flag, null, config);
            JSONObject jsonObjectv2 = payService.wxParseCode(flag, code, config);
            xcxOpenId = jsonObjectv2.get("openid").toString();
        } catch (Throwable e) {
            log.info("获取xcxOpenId失败{}", code);
            throw new ServiceException("获取小程序OpenId失败");
        }
        Map<String, Object> map = new HashMap<>();
        map.put("xcxOpenId", xcxOpenId);
        if (jsonObject != null) {
            String gzhOpenId = (String) jsonObject.get("gzhOpenId");
            if (Arguments.notEmpty(gzhOpenId)) {
                map.put("gzhOpenId", gzhOpenId);
            }
        }
        userInfo.setExtraInfo(JSONObject.toJSONString(map));
        Integer res = userInfoService.updateExtraInfoById(userInfo.getId(), userInfo.getExtraInfo());
        if (res != 1) {
            throw new ServiceException("更新openid失败");
        }
        return xcxOpenId;
    }

    private String alwayGetOpenid(String code, Boolean flag) {
        //公众号
        if (flag) {
            String gzhOpenId = null;
            try {
                MyConfig config = new MyConfig();
                Utility.switchConfig(true, null, config);
                JSONObject jsonObjectv2 = payService.wxParseCode(true, code, config);
                gzhOpenId = jsonObjectv2.get("openid").toString();
            } catch (Throwable e) {
                log.info("获取xcxOpenId失败{}", code);
                throw new ServiceException("获取公众号OpenId失败");
            }
            if (!Arguments.notEmpty(gzhOpenId)) {
                throw new ServiceException("获取公众号OpenId为空");
            }
            return gzhOpenId;
        }
        String xcxOpenId = null;
        try {
            MyConfig config = new MyConfig();
            Utility.switchConfig(flag, null, config);
            JSONObject jsonObjectv2 = payService.wxParseCode(flag, code, config);
            xcxOpenId = jsonObjectv2.get("openid").toString();
        } catch (Throwable e) {
            log.info("获取xcxOpenId失败{}", code);
            throw new ServiceException("获取小程序OpenId失败");
        }
        if (!Arguments.notEmpty(xcxOpenId)) {
            throw new ServiceException("获取小程序OpenId为空");
        }
        return xcxOpenId;
    }

    /**
     * 用户去支付
     *
     * @param token
     * @param orderNo 订单号
     * @param type    支付方式
     * @return
     */
    @ApiOperation(value = "用户去支付", notes = "用户去支付")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "query", name = "token", value = "token", required = true, dataType = "String"),
            @ApiImplicitParam(paramType = "query", name = "orderNo", value = "订单号", required = true, dataType = "String"),
            @ApiImplicitParam(paramType = "query", name = "type", value = "支付类型（wxpay,alipay）", required = true, dataType = "String")
    })
    @RequestMapping(value = "/order/goPay", method = RequestMethod.POST)
    public ResponseEntity<?> goPay(@RequestParam(name = "token") String token,
                                   @RequestParam(name = "orderNo") String orderNo,
                                   @RequestParam(name = "type") String type,
                                   HttpServletRequest request) {
        checkParamOrderNo(orderNo);
//        UserInfo userInfo = accountService.tokenUserInfo(token);
        UserInfo userInfo = userInfoService.tokenUserInfo(token);
        String ip = Utility.getRemoteIP(request);
        Map<String, String> map = orderService.goPay(userInfo, orderNo, type, ip);
        return ResponseEntity.ok(AjaxResponseBody.success(map));
    }

    /**
     * h5用户去支付
     *
     * @param token
     * @param orderNo 订单号
     * @param code code
     * @param sourceType
     * @return
     */
    @ApiOperation(value = "h5用户去支付", notes = "当获取不到openid时code必传")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "query", name = "token", value = "token", required = true, dataType = "String"),
            @ApiImplicitParam(paramType = "query", name = "orderNo", value = "订单号", required = true, dataType = "String"),
            @ApiImplicitParam(paramType = "query", name = "code", value = "code", dataType = "String"),
            @ApiImplicitParam(paramType = "query", name = "sourceType", value = "sourceType", defaultValue = "wx", dataType = "String")
    })
    @RequestMapping(value = "/order/h5/goPay", method = RequestMethod.POST)
    public ResponseEntity<?> h5GoPay(@RequestParam(name = "token") String token,
                                   @RequestParam(name = "orderNo") String orderNo,
                                   @RequestParam(name = "code", required = false) String code,
                                   @RequestParam(name = "sourceType", defaultValue = "wx") String sourceType,
                                   HttpServletRequest request) {
        checkParamOrderNo(orderNo);
        int orderType = PreOrderType.parse(sourceType);
        //true代表是公众号，false代表小程序
        boolean flag = orderType == PreOrderType.wx || orderType == PreOrderType.h5;
        String type = "xcx";
        if (flag) {
            type = "gzh";
        }
//        UserInfo userInfo = accountService.tokenUserInfo(token);
        UserInfo userInfo = userInfoService.tokenUserInfo(token);
        //检测是否该用户是否有openid
        String openId = checkOpenid(userInfo, code, flag);
//        String openId = alwayGetOpenid(code, flag);
        String ip = Utility.getRemoteIP(request);
        Map<String, String> map = orderService.h5GoPay(userInfo, orderNo, type, ip, openId, flag);
        return ResponseEntity.ok(AjaxResponseBody.success(map));
    }

    /**
     * 订单退款(用户申请退款，将订单修改为正在退款状态，并修改退款值)
     *
     * @return
     */
    @ApiOperation(value = "订单退款", notes = "订单退款")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "query", name = "token", value = "token", required = true, dataType = "String"),
            @ApiImplicitParam(paramType = "query", name = "orderNo", value = "订单号", required = true, dataType = "String"),
            @ApiImplicitParam(paramType = "query", name = "reason", value = "退款原因", required = true, dataType = "String")
    })
    @RequestMapping(value = "/order/refundOrder", method = RequestMethod.POST)
    public ResponseEntity<?> refundOrder(@RequestParam(name = "token") String token,
                                         @RequestParam(name = "orderNo") String orderNo,
                                         @RequestParam(name = "reason") String reason) {
        log.info("参数token和orderNo{}{}", token, orderNo);
        if (!Arguments.notEmpty(reason)) {
            throw new ServiceException("退款原因不能为空");
        }
        UserInfo userInfo = accountService.tokenUserInfo(token);
        //通过订单id查询订单
        OrderInfo orderInfo = orderService.selectOrderByOrderNo(orderNo);
        checkOrder(userInfo, orderInfo);
        orderInfo.setStatus(OrderStatus.preRefund);
        orderInfo.setExtraInfo(Utility.setExtraInfo(orderInfo.getExtraInfo(), "refund_reason", reason));
        Integer refundAmount = orderService.getRefundAmount(orderInfo);
//        orderInfo.setSnapshotRefundFee(refundAmount);
        orderInfo.setExtraInfo(Utility.setExtraInfo(orderInfo.getExtraInfo(), "refund_fee", refundAmount));
        Integer res = orderService.updateByPrimaryKey(orderInfo);
        if (res != 1) {
            throw new ServiceException("修改订单状态为待退款失败");
        }
        //发送相关短信
        refundSms(orderInfo);
        //推送订单退款通知
//        webSocket.sendMessage("客户发送退款申请，请前去处理");
        return ResponseEntity.ok(AjaxResponseBody.success());
    }

    private void refundSms(OrderInfo orderInfo) {
        RoomInfo roomInfo = roomInfoService.selectByPrimaryKey(orderInfo.getRoomId());
        if (roomInfo == null) {
            log.info("该订单对应房间不存在orderNo = {}", orderInfo.getOrderNo());
            throw new ServiceException("该订单对应房间不存在");
        }
        HotelInfo hotelInfo = hotelService.selectHotelInfoById(roomInfo.getHotelId());
        if (hotelInfo == null) {
            log.info("该订单对应酒店不存在orderNo = {}", orderInfo.getOrderNo());
            throw new ServiceException("该订单对应酒店不存在");
        }
        //用户退款给酒店发送短信，并推送消息
        String phone = hotelService.getSmsPhoneByHotelInfo(hotelInfo);
        Map<String, String> map = orderService.getNameAndPhoneByOrderInfo(orderInfo);
        String person = map.get("name");
//        String daytime = DateUtils.format(DateUtils.afterHoursToDate(orderInfo.getCheckIn(), 12L));
        String daytime = DateUtils.toYYMMddStr(orderInfo.getCheckIn());
        String hotelname = hotelInfo.getName();
        String roomtype = roomInfo.getTitle();
        smsService.sendSmsForUserRefund(phone, person, daytime, hotelname, roomtype);
    }

    /**
     * 获取用户应该退款的金额
     *
     * @return
     */
    @ApiOperation(value = "获取用户应该退款的金额", notes = "获取用户应该退款的金额")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "query", name = "token", value = "token", required = true, dataType = "String"),
            @ApiImplicitParam(paramType = "query", name = "orderNo", value = "订单号", required = true, dataType = "String")
    })
    @RequestMapping(value = "/order/refundAmount", method = RequestMethod.POST)
    public ResponseEntity<?> refundAmount(@RequestParam(name = "token") String token,
                                          @RequestParam(name = "orderNo") String orderNo) {
        log.info("参数token和orderNo{}{}", token, orderNo);
        UserInfo userInfo = accountService.tokenUserInfo(token);
        //通过订单id查询订单
        OrderInfo orderInfo = orderService.selectOrderByOrderNo(orderNo);
        checkOrder(userInfo, orderInfo);
        Integer refundAmount = orderService.getRefundAmount(orderInfo);
        Map<String, Integer> map = new HashMap<>();
        map.put("refundAmount", refundAmount);
        map.put("totalFee", orderInfo.getSnapshotTotalFee());
        return ResponseEntity.ok(AjaxResponseBody.success(map));
    }

    /**
     * 获取退款说明和退款原因
     *
     * @return
     */
    @ApiOperation(value = "获取退款说明和退款原因", notes = "获取退款说明和退款原因")
    @RequestMapping(value = "/refund/desc", method = RequestMethod.POST)
    public ResponseEntity<?> refundDesc() {
        String desc = configService.getValue(ConfigKey.REFUND_EXPLAIN);
        String reason = configService.getValue(ConfigKey.REFUND_REASON);
        Map<String, List<String>> map = new HashMap<>();
        map.put("desc", Splitters.splitToString(desc, Splitters.COMMA));
        map.put("reason", Splitters.splitToString(reason, Splitters.COMMA));
        return ResponseEntity.ok(AjaxResponseBody.success(map));
    }

    /**
     * 获取退款原因
     *
     * @return
     */
    @ApiIgnore
    @RequestMapping(value = "/refund/reason", method = RequestMethod.POST)
    public ResponseEntity<?> refundReason() {
        String value = configService.getValue(ConfigKey.REFUND_REASON);
        return ResponseEntity.ok(AjaxResponseBody.success(Splitters.splitToString(value, Splitters.COMMA)));
    }

    /**
     * 用户给酒店评分
     *
     * @param token
     * @param orderNo
     * @param score
     * @return
     */
    @ApiOperation(value = "用户给酒店评分", notes = "用户给酒店评分")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "query", name = "token", value = "token", required = true, dataType = "String"),
            @ApiImplicitParam(paramType = "query", name = "orderNo", value = "订单号", required = true, dataType = "String"),
            @ApiImplicitParam(paramType = "query", name = "score", value = "评分", required = true, dataType = "int")
    })
    @RequestMapping(value = "/order/evaluate", method = RequestMethod.POST)
    public ResponseEntity<?> orderEvaluate(@RequestParam(name = "token") String token,
                                           @RequestParam(name = "orderNo") String orderNo,
                                           @RequestParam(name = "score", defaultValue = "100") Integer score) {
        UserInfo userInfo = accountService.tokenUserInfo(token);
        OrderInfo orderInfo = orderService.selectOrderByOrderNo(orderNo);
        if (orderInfo == null) {
            log.info("该订单不存在orderNo = {}", orderNo);
            throw new ServiceException("该订单不存在");
        }
        if (!orderInfo.getUserId().equals(userInfo.getId())) {
            throw new ServiceException("非本人订单不能操作");
        }
        if (!orderInfo.getStatus().equals(OrderStatus.postCheckOut)) {
            throw new ServiceException("非完成订单不能评价");
        }
        int rec = orderService.updateScoreAndStatusByOrderNo(orderNo, score, OrderStatus.comment);
        if (rec != 1) {
            throw new ServiceException("用户评分更新失败");
        }
        Integer hotelId = orderService.getHotelIdByOrderNo(orderNo);
        if (hotelId == null || hotelId == 0) {
            throw new ServiceException("该订单对应酒店不存在");
        }
        rec = hotelService.updateScore(hotelId);
        if (rec == 0) {
            throw new ServiceException("更新酒店评分失败");
        }
        return ResponseEntity.ok(AjaxResponseBody.success());
    }

    /**
     * 用户上传头像
     *
     * @return
     */
    @ApiOperation(value = "用户上传头像", notes = "用户上传头像")
    @PostMapping(value = "/upload/avatar")
    public ResponseEntity<?> uploadAvatar(@ApiParam(value = "token", name = "token", required = true) @RequestParam(name = "token") String token,
                                          @ApiParam(value = "上传的文件", name = "file", required = true) @RequestParam(name = "file") MultipartFile file) {
        UserInfo userInfo = accountService.tokenUserInfo(token);
        Map<String, Object> map = ossUpload(userInfo.getId(), file);
        if (map.size() == 0) {
            throw new ServiceException("文件上传失败");
        }
        String url = (String) map.get("url");
        Integer res = userInfoService.updateAvatar(userInfo.getId(), url);
        if (res != 1) {
            throw new ServiceException("更新用户头像失败");
        }
        return ResponseEntity.ok(AjaxResponseBody.success(map));
    }

    /**
     * 用户充值
     *
     * @return
     */
    @ApiOperation(value = "用户充值", notes = "用户充值")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "query", name = "token", value = "token", required = true, dataType = "String"),
            @ApiImplicitParam(paramType = "query", name = "price", value = "充值金额", required = true, dataType = "int"),
            @ApiImplicitParam(paramType = "query", name = "inviteId", value = "邀请码", dataType = "String"),
            @ApiImplicitParam(paramType = "query", name = "type", value = "支付类型（wxpay,alipay）", required = true, dataType = "String")
    })
    @PostMapping(value = "/vip/pay")
    public ResponseEntity<?> vipPay(@RequestParam(name = "token") String token,
                                    @RequestParam(name = "price") Integer price,
                                    @RequestParam(name = "inviteId", required = false) String inviteId,
                                    @RequestParam(name = "type") String type,
                                    HttpServletRequest request) {
        UserInfo userInfo = accountService.tokenUserInfo(token);
        Map<String, String> map = vipOrderService.vipPay(userInfo, inviteId, price, type, Utility.getRemoteIP(request));
        return ResponseEntity.ok(AjaxResponseBody.success(map));
    }

    /**
     * h5用户充值
     *
     * @param token
     * @param code code
     * @param sourceType
     * @return
     */
    @ApiOperation(value = "h5用户充值", notes = "当获取不到openid时code必传")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "query", name = "token", value = "token", required = true, dataType = "String"),
            @ApiImplicitParam(paramType = "query", name = "code", value = "code", dataType = "String"),
            @ApiImplicitParam(paramType = "query", name = "price", value = "充值金额", required = true, dataType = "int"),
            @ApiImplicitParam(paramType = "query", name = "inviteId", value = "邀请码", dataType = "String"),
            @ApiImplicitParam(paramType = "query", name = "sourceType", value = "sourceType", defaultValue = "wx", dataType = "String")
    })
    @RequestMapping(value = "/h5/vip/Pay", method = RequestMethod.POST)
    public ResponseEntity<?> h5VipPay(@RequestParam(name = "token") String token,
                                     @RequestParam(name = "code", required = false) String code,
                                     @RequestParam(name = "price") Integer price,
                                     @RequestParam(name = "inviteId", required = false) String inviteId,
                                     @RequestParam(name = "sourceType", defaultValue = "wx") String sourceType,
                                     HttpServletRequest request) {
        int orderType = PreOrderType.parse(sourceType);
        //true代表是公众号，false代表小程序
        boolean flag = orderType == PreOrderType.wx || orderType == PreOrderType.h5;
        String type = "xcx";
        if (flag) {
            type = "gzh";
        }
        UserInfo userInfo = accountService.tokenUserInfo(token);
        //检测是否该用户是否有openid
        String openId = checkOpenid(userInfo, code, flag);
        String ip = Utility.getRemoteIP(request);
        Map<String, Object> map = vipOrderService.h5VipPay(userInfo, inviteId, price, type, ip, openId, flag);
        return ResponseEntity.ok(AjaxResponseBody.success(map));
    }

    /**
     * 充值取消后去支付
     *
     * @param token
     * @param orderNo 订单号
     * @param type    支付方式
     * @return
     */
    @ApiOperation(value = "充值取消后去支付", notes = "充值取消后去支付")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "query", name = "token", value = "token", required = true, dataType = "String"),
            @ApiImplicitParam(paramType = "query", name = "orderNo", value = "订单号", required = true, dataType = "String"),
            @ApiImplicitParam(paramType = "query", name = "type", value = "支付类型（wxpay,alipay）", required = true, dataType = "String")
    })
    @RequestMapping(value = "/vip/goPay", method = RequestMethod.POST)
    public ResponseEntity<?> vipGoPay(@RequestParam(name = "token") String token,
                                      @RequestParam(name = "orderNo") String orderNo,
                                      @RequestParam(name = "type") String type,
                                      HttpServletRequest request) {
        checkParamOrderNo(orderNo);
        UserInfo userInfo = accountService.tokenUserInfo(token);
        String ip = Utility.getRemoteIP(request);
        Map<String, String> map = vipOrderService.goPay(userInfo, orderNo, type, ip);
        return ResponseEntity.ok(AjaxResponseBody.success(map));
    }

    /**
     * 通过订单号查询该订单是否付款成功
     *
     * @param orderNo 订单号
     * @return
     */
    @ApiOperation(value = "通过订单号查询该订单是否付款成功", notes = "body中返回true或false")
    @ApiImplicitParam(paramType = "query", name = "orderNo", value = "订单号", required = true, dataType = "String")
    @RequestMapping(value = "/order/success", method = RequestMethod.POST)
    public ResponseEntity<?> orderSuccess(@RequestParam(name = "orderNo") String orderNo) {
        checkParamOrderNo(orderNo);
        Boolean flag = false;
        OrderInfo orderInfo = orderService.selectOrderByOrderNo(orderNo);
        if (orderInfo != null) {
            if (orderInfo.getStatus().equals(OrderStatus.preCheckIn)
                    || orderInfo.getStatus().equals(OrderStatus.living)) {
                flag = true;
            }
        }
        if (!flag) {
            VipOrder vipOrder = vipOrderService.selectOrderByOrderNo(orderNo);
            if (vipOrder != null) {
                if (vipOrder.getStatus().equals(VipOrderStatus.postPay)) {
                    flag = true;
                }
            }

        }
        return ResponseEntity.ok(AjaxResponseBody.success(flag));
    }

    /**
     * 获取分享文案
     *
     * @return
     */
    @ApiOperation(value = "获取分享文案", notes = "获取分享文案")
    @RequestMapping(value = "/share/content", method = RequestMethod.POST)
    public ResponseEntity<?> shareContent() {
        String value = configService.getValue(ConfigKey.SHARE_CONTENT);
        if (!Arguments.notEmpty(value)) {
            return ResponseEntity.ok(AjaxResponseBody.success(new HashMap<>()));
        }
        return ResponseEntity.ok(AjaxResponseBody.success(JSONObject.parseObject(value)));
    }

    /**
     * 获取充值10元得两张50元券的截止日期
     *
     * @return
     */
    @ApiOperation(value = "获取充值10元得两张50元券的截止日期", notes = "获取充值10元得两张50元券的截止日期")
    @ApiImplicitParam(paramType = "query", name = "price", value = "充值的金额", dataType = "int")
    @RequestMapping(value = "/coupon/overTime/image", method = RequestMethod.POST)
    public ResponseEntity<?> couponOverTimeImage(@RequestParam(name = "price", defaultValue = "1000") Integer price) {
        CouponInfo couponInfo = couponInfoService.selectCouponByPayAmount(price);
        if (couponInfo == null) {
            throw new ServiceException("该优惠券不存在");
        }
        String overTime = DateUtils.format(couponInfo.getValidEnd());
        return ResponseEntity.ok(AjaxResponseBody.success(overTime));
    }

    /**
     * 获取充值链接
     *
     * @return
     */
    @ApiOperation(value = "获取充值链接", notes = "获取充值链接")
    @RequestMapping(value = "/pay/url", method = RequestMethod.POST)
    public ResponseEntity<?> payUrl() {
        String value = configService.getValue(ConfigKey.PAY_URL);
        return ResponseEntity.ok(AjaxResponseBody.success(value));
    }

    /**
     * 订单详情
     *
     * @param orderNo 订单号
     * @return
     */
    @ApiOperation(value = "订单详情", notes = "订单详情", response = OrderDetailDTO.class)
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "query", name = "token", value = "token", required = true, dataType = "String"),
            @ApiImplicitParam(paramType = "query", name = "orderNo", value = "订单号", required = true, dataType = "String")
    })
    @RequestMapping(value = "/order/detail", method = RequestMethod.POST)
    public ResponseEntity<?> detail(@RequestParam(name = "token") String token,
                                    @RequestParam(name = "orderNo") String orderNo) {
        checkParamOrderNo(orderNo);
        OrderInfo orderInfo = orderService.selectOrderByOrderNo(orderNo);
        if (orderInfo == null) {
            log.info("该订单不存在orderNo = {}", orderNo);
            throw new ServiceException("该订单不存在");
        }
        UserInfo userInfo = accountService.tokenUserInfo(token);
        if (!userInfo.getId().equals(orderInfo.getUserId())) {
            throw new ServiceException("非本人订单，拒绝操作");
        }
        OrderDetailDTO detail = orderService.detail(orderInfo);
        return ResponseEntity.ok(AjaxResponseBody.success(detail));
    }

    /**
     * 用户分享
     *
     * @param token
     * @param type
     * @return
     */
    @ApiOperation(value = "用户分享", notes = "用户分享")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "query", name = "token", value = "token", required = true, dataType = "String"),
            @ApiImplicitParam(paramType = "query", name = "type", value = "分享类型(微博WEIBO，朋友圈TIMELINE，微信APP_MESSAGE)", required = true, dataType = "String")
    })
    @RequestMapping(value = "/share/add", method = RequestMethod.POST)
    public ResponseEntity<?> add(
            @RequestParam(name = "token") String token,
            @RequestParam(name = "type") String type) {
        UserInfo accountInfo = accountService.tokenUserInfo(token);
        ShareLog shareLog = new ShareLog();
        shareLog.setUserId(accountInfo.getId());
        shareLog.setShareType(type.toUpperCase());
        shareLog.setGmtCreate(new Date());
        int insert = shareLogService.insert(shareLog);
        if (insert != 1) {
            log.info("分享更新数据失败");
            throw new ServiceException("更新数据失败");
        }
        return ResponseEntity.ok(AjaxResponseBody.success());
    }

    /**
     * 获取版本信息
     *
     * @return
     */
    @ApiOperation(value = "获取版本信息", notes = "获取版本信息", response = AppInfoDTO.class)
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "query", name = "version", value = "version", required = true, dataType = "String"),
            @ApiImplicitParam(paramType = "query", name = "type", value = "类型(iOS,Android)", required = true, dataType = "String")
    })
    @RequestMapping(value = "/system/version", method = RequestMethod.POST)
    public ResponseEntity<?> systemVersion(@RequestParam(value = "version") String version,
                                           @RequestParam(value = "type") String type) {
        if (!Arguments.notEmpty(version)) {
            throw new ServiceException("版本号不能为空");
        }
        AppInfoDTO appInfoDTO = appInfoService.getAppInfoByType(type, version);
        return ResponseEntity.ok(AjaxResponseBody.success(appInfoDTO));
    }

    /**
     * 获取曹超专车的sign
     *
     * @return
     */
    @ApiOperation(value = "获取曹超专车的sign", notes = "获取曹超专车的sign")
    @ApiImplicitParam(paramType = "query", name = "token", value = "token", required = true, dataType = "String")
//    @ApiImplicitParams({
//            @ApiImplicitParam(paramType = "query", name = "token", value = "token", required = true, dataType = "String"),
//            @ApiImplicitParam(paramType = "query", name = "clientId", value = "clientId", required = true, dataType = "String"),
//            @ApiImplicitParam(paramType = "query", name = "signKey", value = "signKey", required = true, dataType = "String")
//    })
    @RequestMapping(value = "/cczc/sign", method = RequestMethod.POST)
    public ResponseEntity<?> cczcSign(@RequestParam(value = "token") String token) {
        UserInfo accountInfo = accountService.tokenUserInfo(token);
        Integer userId = accountInfo.getId();
        Map<String, String> map = cczcService.getSign(userId);
        return ResponseEntity.ok(AjaxResponseBody.success(map));
    }


    /**
     * 测试vip券
     *
     * @param token
     * @param payAmount
     * @return
     */
    @ApiIgnore
    @RequestMapping(value = "/test/get/vip", method = RequestMethod.POST)
    public ResponseEntity<?> userSetPwd(@RequestParam(name = "token") String token,
                                        @RequestParam(name = "payAmount") Integer payAmount
    ) {
        UserInfo operatorInfo = accountService.tokenUserInfo(token);
        userInfoService.createVIP(operatorInfo.getId(), payAmount);
        return ResponseEntity.ok(AjaxResponseBody.success());
    }

    /**
     * 测试子查父
     *
     * @return
     */
    @ApiOperation(value = "测试子查父", notes = "测试子查父")
    @RequestMapping(value = "/test/child/parent", method = RequestMethod.POST)
    public ResponseEntity<?> testChildParent() {
        return ResponseEntity.ok(AjaxResponseBody.success(accountService.getParentId(1705)));
    }

    private ResponseEntity<?> packLoginResult(UserInfo userInfo) {
        UserInfoDTO userInfoDTO = ObjectConvertUtil.convertObject(userInfo, UserInfoDTO.class);
        // 用户ID生成Token
        String token = accountService.userId2Token(userInfo.getId());
        // 生成结果
        Map<String, Object> res = new HashMap<>();
        res.put("user_info", userInfoDTO);
        res.put("token", token);
        //通过用户id查询该用户是否是vip,type = 1普通vip，2超级vip，3至尊vip
        VipInfo vipInfo = vipInfoService.selectVipInfoByUserIdAndType(userInfo.getId(), null);
        if (vipInfo != null) {
            userInfoDTO.setVipStatus(vipInfo.getType());
        }
        return ResponseEntity.ok(AjaxResponseBody.success(res));
    }

    private void checkParamPhone(String phone) {
        if (Arguments.isEmpty(phone)) {
            throw new ServiceException("手机号不能为空");
        }
        if (!TextValidator.MOBILE.boolCheck(phone)) {
            throw new ServiceException("手机号格式非法");
        }
    }

    private void checkParamPhoneUseId(String phone, Integer userId) {
        if (Arguments.isEmpty(phone)) {
            throw new ServiceException("手机号不能为空");
        }
        if (!TextValidator.MOBILE.boolCheck(phone)) {
            throw new ServiceException("手机号格式非法");
        }
        if (Arguments.isNullOrZero(userId)) {
            throw new ServiceException("分享人id不能为空");
        }
    }

    private void checkParamAvatar(String avatar) {
        if (Arguments.isEmpty(avatar)) {
            throw new ServiceException("头像输入不能为空");
        }
    }

    private void checkParamOrderNo(String orderNo) {
        if (Arguments.isEmpty(orderNo)) {
            throw new ServiceException("订单号不能为空");
        }
    }

    private void checkParamPwd(String password) {
        if (Arguments.isEmpty(password)) {
            throw new ServiceException("密码输入为空");
        }
        if (password.length() < 6 || password.length() > 16) {
            throw new ServiceException("密码的有效长度为6-16位");
        }
    }

    private void checkParamPhonePwd(String phone, String password) {
        if (Arguments.isEmpty(phone)) {
            throw new ServiceException("手机号不能为空");
        }
        if (!TextValidator.MOBILE.boolCheck(phone)) {
            throw new ServiceException("手机号格式非法");
        }
        if (Arguments.isEmpty(password)) {
            throw new ServiceException("密码输入为空");
        }
        if (password.length() < 6 || password.length() > 16) {
            throw new ServiceException("密码的有效长度为6-16位");
        }
    }

    private OrderInfo getOrderInfo(String name, String phone) {
        if (!Arguments.notEmpty(name)) {
            throw new ServiceException("用户真实姓名不能为空");
        }
        name = name.replaceAll("\\n", "");
        name = name.replaceAll("\\s", "");
        if (!Arguments.notEmpty(name)) {
            throw new ServiceException("用户真实姓名不能为空");
        }
        if (!Arguments.notEmpty(phone)) {
            throw new ServiceException("用户手机号不能为空");
        }
        if (!TextValidator.MOBILE.boolCheck(phone)) {
            throw new ServiceException("手机号格式不正确");
        }
        OrderInfo orderInfo = new OrderInfo();
        Map<String, String> map = new HashMap<>();
        map.put("name", name);
        map.put("phone", phone);
        orderInfo.setVitalPersonInfo(JSONObject.toJSON(map).toString());
        return orderInfo;
    }

    private void checkOrder(UserInfo userInfo, OrderInfo orderInfo) {
        if (orderInfo == null) {
            throw new ServiceException("该订单不存在");
        }
        if (!userInfo.getId().equals(orderInfo.getUserId())) {
            throw new ServiceException("非本人订单");
        }
        if (!orderInfo.getStatus().equals(OrderStatus.preCheckIn)) {
            throw new ServiceException("该订单非待入住状态");
        }
    }

    private Map<String, Object> ossUpload(Integer userId, MultipartFile file) {

        Map<String, Object> result = new HashMap<>();
        try {
            if (!file.isEmpty()) {
                String filename = file.getOriginalFilename();
                String newName = getFileName(FilenameUtils.getExtension(filename));
                String ossKey = "User/" + userId.toString() + "/" + newName;
                if (ossService.writeOSS(file.getBytes(), ossKey)) {
                    result.put("url", ossService.getPrefixUrl() + ossKey);
                    return result;
                }
            }
        } catch (Exception e) {
            log.info("文件上传出错{}", e.getLocalizedMessage());
            return result;
        }
        return result;
    }

    /**
     * 通过原始名称获取随机名称的图片名
     */
    private static String getFileName(String ext) {
        Date date = new Date(System.currentTimeMillis());
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddHHmmssSSS");
        String name = simpleDateFormat.format(date);
        return name + getSixNumStr() + "." + ext;
    }

    /**
     * 获取六位数字随机数
     */
    private static String getSixNumStr() {
        Random random = new Random();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < 6; i++) {
            sb.append(random.nextInt(10));
        }
        return sb.toString();
    }

}

